iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
Software Development

Rails Active Model系列 第 12

D-12 Active Model 自定義可共用的 validator - 3

  • 分享至 

  • xImage
  •  

這篇接續上一篇來介紹,該如何定義你的 validation helper method。

通過 source code 幾個 helper method 的定義,我們可以發現他們都有固定的模式

這邊參考 rails activemodel/lib/active_model/validations/presence.rb

module ActiveModel
  module Validations
    class PresenceValidator < EachValidator
      def validate_each(record, attr_name, value)
        record.errors.add(attr_name, :blank, options) if value.blank?
      end
    end

    module HelperMethods
      # ... 很多 comments
      def validates_presence_of(*attr_names)
        validates_with PresenceValidator, _merge_attributes(attr_names)
      end
    end
  end
end

沒錯!除了都在 ActiveModel::Validations 底下建立 validator 之外,
還有在 ActiveModel::Validations::HelperMethods 底下去 define 他的 helper method

但其實延續上一篇講的,const_get 的功能是會往外一層一層找 constant ,所以您的 validator 不一定要跟隨 rails 的腳步定義在 ActiveModel::Validations 裡面,

但您的 validation helper method 如果想做到全專案共用,就一定要設在 ActiveModel::Validations::HelperMethods 裡面!

而且還不僅止於此,因為這個 validation helper method 您勢必要用在你的 class definition 階段,所以一定要早在 rails autoload 之前去定義這些 method。

對沒錯,你需要放在 config/initializers 裡面。

For example,延續上一篇的 csv headers validator

path: app/validators/headers_validator.rb

class HeadersValidator < ActiveModel::EachValidator
  def validate_each(record, attr_name, csv)
    return if (options[:in] & csv.headers) == options[:in]
    record.errors.add(attr_name, :invalid_headers)
  end

  def check_validity!
    unless options[:in].is_a?(Array)
      raise "should be array."
    end
  end
end

然後在 initializers 裡面去定義:
path: config/initializers/validations.rb

module ActiveModel
  module Validations
    module HelperMethods
      def validates_headers_of(*attr_names)
        validates_with HeadersValidator, _merge_attributes(attr_names)
      end
    end
  end
end

這樣,你的 Active Model 就會多出一個 validates_headers_of 的神奇功能可以用啦~

依照上述範例,使用方式就像這樣:

class MyClass
  include ActiveModel::Model

  validates_headers_of :csv, in: ["name", "age"]

  def csv
    # your_file 考考讀者您要怎麼定義,反正就是傳個檔案進來
    @csv ||= CSV.parse(your_file, headers: true)
  end
end

至此,validator 系列就算告一段落啦~!


上一篇
D-11 Active Model 自定義可共用的 validator - 2
下一篇
D-13 Active Model - 自訂義資料轉換器 - 1
系列文
Rails Active Model28
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言